package org.despair2D.ui.core
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.system.Capabilities;
	import flash.system.TouchscreenType;
	import flash.ui.Mouse;
	import flash.ui.Multitouch;
	
	import org.despair2D.Despair;
	import org.despair2D.Observer;
	import org.despair2D.control.TouchManager;
	import org.despair2D.control.ZMouseEvent;
	import org.despair2D.core.IFrameListener;
	import org.despair2D.core.ProcessManager;
	import org.despair2D.core.ns_despair;
	import org.despair2D.debug.Logger;
	import org.despair2D.ui.core.Component;
	import org.despair2D.ui.core.IComponent;
	import org.despair2D.ui.core.SpriteAdvance;
	import org.despair2D.ui.events.ManipulateEvent;
	import org.despair2D.ui.puppet.supportClasses.PuppetComp;
	import org.despair2D.ui.supportClasses.AbstractButton;

	use namespace ns_despair;
	
final public class UIManager implements IFrameListener
{

	public function UIManager( simulationWidth:int, simulationHeight:int, landscape:Boolean )
	{
		var ratioHoriz:Number, ratioVerti:Number, width:Number, height:Number
		
		if (Multitouch.maxTouchPoints == 0)
		{
			m_pixelRatio = 1
		}
		else
		{
			if (landscape)
			{
				width   =  Math.max(Capabilities.screenResolutionX, Capabilities.screenResolutionY)
				height  =  Math.min(Capabilities.screenResolutionX, Capabilities.screenResolutionY)
			}
			else
			{
				width   =  Math.min(Capabilities.screenResolutionX, Capabilities.screenResolutionY)
				height  =  Math.max(Capabilities.screenResolutionX, Capabilities.screenResolutionY)
			}
			ratioHoriz    =  width  / simulationWidth
			ratioVerti    =  height / simulationHeight
			m_pixelRatio  =  (ratioHoriz > ratioVerti) ? ratioVerti : ratioHoriz
		}
		
		m_screenWidth   =  Despair.stage.stageWidth  / m_pixelRatio
		m_screenHeight  =  Despair.stage.stageHeight / m_pixelRatio
	}
	
	
	/** 触碰优先级 **/
	ns_despair static const PRIORITY:int = 800
	
	
	ns_despair static function get hoveredElement()  : IComponent { return getProxy(m_hoveredCid) }
	ns_despair static function get pressedElement()  : IComponent { return getProxy(m_pressedCid) }
	
	
	ns_despair static function getProxy( cid:uint ) : IComponent
	{
		var C:Component = m_registeredCompList[cid];
		return C ? C.m_proxy as IComponent : null;
	}
	
	final ns_despair function initializeUI() : void
	{
		TouchManager.getInstance().addEventListener(ZMouseEvent.MOUSE_PRESS,   ____onMouseMessage, false, PRIORITY )
		TouchManager.getInstance().addEventListener(ZMouseEvent.MOUSE_RELEASE, ____onMouseMessage, false, PRIORITY )
		TouchManager.getInstance().addEventListener(ZMouseEvent.MOUSE_MOVE,    ____onMouseMessage, false, PRIORITY )
		m_interactive = true
		
		ProcessManager.addFrameListener(this, ProcessManager.RETRIEVE)
	}
	
	final ns_despair function addMonitor() : void
	{
		m_monitor = new Sprite()
		m_monitor.mouseEnabled  =  m_monitor.mouseChildren  =  false
		m_monitor.tabEnabled    =  m_monitor.tabChildren    =  false
		
		m_stage.addChildAt(m_monitor, 0)
		if (m_pixelRatio != 1)
		{
			m_monitor.scaleX = m_monitor.scaleY = m_pixelRatio
		}
	}
	
	ns_despair static function reset() : void
	{
		var element:IComponent
		
		element = hoveredElement
		if (element && element.fusion is AbstractButton)
		{
			(element.fusion as AbstractButton).resetButton()
		}
		element = pressedElement
		if (element && element.fusion is AbstractButton)
		{
			(element.fusion as AbstractButton).resetButton()
		}
	}
	
	ns_despair static function registerComp( comp:Component ) : void
	{
		m_registeredCompList[++m_numRegistered]  =  comp;
		comp.m_cid                               =  m_numRegistered;
	}
	
	ns_despair function registerPanel( panelName:String, stateType:Class ) : void
	{
		if (m_panelList[panelName])
		{
			Logger.reportError('PanelManager', 'registerPanel', 'Registered Panel: ' + panelName)
		}
		m_panelList[panelName] = new PanelProp(stateType)
	}
	
	ns_despair function getPanel( panelName:String ) : IPanel
	{
		return m_panelList[panelName]
	}
	
	ns_despair function killAllPanels() : void
	{
		var key:*
		var panel:PanelProp
		
		for (key in m_panelList)
		{
			panel = m_panelList[key]
			if (panel.m_multiFusion)
			{
				panel.close()
			}
		}
	}
	
	
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	
	
	ns_despair static var m_registeredCompList:Vector.<Component> = new Vector.<Component>(44444, true);
	
	ns_despair static var m_numRegistered:int;
	
	ns_despair static var cachedPoint:Point = new Point();
	
	ns_despair static var m_stage:Stage
	
	ns_despair static var m_monitor:Sprite
	
	ns_despair static var m_hoveredCid:uint, m_pressedCid:uint
	
	ns_despair static var m_objectList:Array = []
	
	ns_despair static var m_invalidWhenLeave:Boolean, m_interactive:Boolean
	
	ns_despair static var m_pixelRatio:Number
	
	ns_despair static var m_simulationDPI:Number
	
	ns_despair static var m_screenWidth:Number, m_screenHeight:Number
	
	ns_despair var m_nullPressedObserver:Observer
	
	ns_despair var m_panelList:Object = new Object()
	
	
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////
	
	
	final public function update( deltaTime:Number ) : void
	{
		if (TouchManager.getInstance().isTouched)
		{
			cachedPoint.x  =  TouchManager.getInstance().touchX
			cachedPoint.y  =  TouchManager.getInstance().touchY
			m_objectList   =  m_monitor.getObjectsUnderPoint(cachedPoint);
		}
		//Logger.reportWarning(this,'update','touch true')
		//else
		//{
			//Logger.reportWarning(this,'update','touch false')
		//}
	}
	
	/**
	 * 更新交互状态
	 * 
	 * @usage	按下组件，再滑出组件，此时按下动作失效.
	 */
	final ns_despair function ____onMouseMessage( event:ZMouseEvent ) : void
	{
		var PT:PuppetComp, oldPT:PuppetComp;
		var cid:uint, l:int
		var target:DisplayObject
		var parent:DisplayObjectContainer
		var type:String
		
		type  =  event.type
		// debug !!
		//trace(type + ' | ' + m_objectList)
		
		if (!m_interactive)
		{
			return
		}
		
		else if(type == ZMouseEvent.MOUSE_PRESS)
		{
//			Logger.reportWarning(this,'stage', m_stage.mouseX + ' | ' + m_stage.mouseY)
//			Logger.reportWarning(this,'old', TouchManager.getInstance().touchX + ' | ' + TouchManager.getInstance().touchY)
			cachedPoint.x  =  TouchManager.getInstance().touchX
			cachedPoint.y  =  TouchManager.getInstance().touchY
			m_objectList   =  m_monitor.getObjectsUnderPoint(cachedPoint);
		}
		
		l = m_objectList.length
		while (--l > -1)
		{
			target  =  m_objectList[l];
			parent  =  target.parent
			while (parent && !Boolean(parent is SpriteAdvance))
			{
				parent = parent.parent
			}
			PT = parent as PuppetComp
			
			// 外部显示对象
			if (!PT)
			{
				event.stopImmediatePropagation()
				break
			}
			
			if (PT.interactiveZ)
			{
				// 停止传播
				event.stopImmediatePropagation()
				
				switch(type)
				{
					case ZMouseEvent.MOUSE_PRESS:
						m_hoveredCid = m_pressedCid = PT.m_cid
						PT.bubble(new ManipulateEvent(ManipulateEvent.PRESS));
						//Logger.reportMessage(this, 'press' + ' | ' + m_objectList)
						return;
						
					case ZMouseEvent.MOUSE_RELEASE:
						cid           =  m_pressedCid
						m_pressedCid  =  m_hoveredCid = 0
						oldPT         =  m_registeredCompList[cid] as PuppetComp
						
						if (oldPT && oldPT.interactiveZ)
						{
							oldPT.bubble(new ManipulateEvent(ManipulateEvent.RELEASE))
						}
						
						else if (PT != oldPT)
						{
							PT.bubble(new ManipulateEvent(ManipulateEvent.RELEASE))	
						}
						//Logger.reportMessage(this, 'release' + ' | ' + m_objectList)
						
						if (PT.m_cid == cid)
						{
							PT.bubble(new ManipulateEvent(ManipulateEvent.CLICK))
							//Logger.reportMessage(this, 'click' + ' | ' + m_objectList)
						}
						
						return;
						
					case ZMouseEvent.MOUSE_MOVE:
						cid = PT.m_cid
						if (cid != m_hoveredCid)
						{
							if (m_hoveredCid > 0)
							{
								if (cid == m_pressedCid && m_invalidWhenLeave)
								{
									m_pressedCid = 0
								}
								
								oldPT = m_registeredCompList[m_hoveredCid] as PuppetComp
								if (oldPT && oldPT.interactiveZ && oldPT.stage)
								{
									m_hoveredCid = 0
									oldPT.bubble(new ManipulateEvent(ManipulateEvent.LEAVE));
								}
							}
							m_hoveredCid = cid
							PT.bubble(new ManipulateEvent(ManipulateEvent.OVER));
						}
						
						PT.bubble(new ManipulateEvent(ManipulateEvent.MOVE));
						
						return;
				}
			}
		}
		
		if (type == ZMouseEvent.MOUSE_MOVE && m_hoveredCid > 0)
		{
			oldPT         =  m_registeredCompList[m_hoveredCid] as PuppetComp;
			m_hoveredCid  =  0;
			
			if (oldPT && oldPT.interactiveZ && oldPT.stage)
			{
				oldPT.bubble(new ManipulateEvent(ManipulateEvent.LEAVE));
			}
			
			if (m_pressedCid > 0 && m_invalidWhenLeave)
			{
				m_pressedCid = 0
			}
		}
		
		else if (type == ZMouseEvent.MOUSE_PRESS && m_nullPressedObserver)
		{
			m_nullPressedObserver.execute()
		}
		
		else if(type == ZMouseEvent.MOUSE_RELEASE && m_pressedCid > 0)
		{
			oldPT         =  m_registeredCompList[m_pressedCid] as PuppetComp;
			m_pressedCid  =  0;
			
			if (oldPT && oldPT.interactiveZ && oldPT.stage)
			{
				oldPT.bubble(new ManipulateEvent(ManipulateEvent.RELEASE));
			}
		}
	}
	
}
}
import flash.events.EventDispatcher;

import org.despair2D.core.INextUpdater;
import org.despair2D.core.NextUpdaterManager;
import org.despair2D.core.ProcessManager;
import org.despair2D.core.ns_despair;
import org.despair2D.ui.MultiFusion;
import org.despair2D.ui.core.IPanel;
import org.despair2D.ui.core.UIManager;
import org.despair2D.ui.events.PanelEvent;
use namespace ns_despair;
	
final class PanelProp extends EventDispatcher implements IPanel, INextUpdater
{
	
	public function PanelProp( stateType:Class )
	{
		super(null)
		m_stateType = stateType
	}
	
	
	final public function get isPopup():Boolean
	{
		return m_multiFusion && m_multiFusion.displayObject.stage
	}
	
	
	final public function popup( layer:int = -1, immediate:Boolean = true, stateArgs:Array = null ) : void
	{
		m_layer = layer
		mStateArgs = stateArgs
		
		if (immediate)
		{
			if (m_isReadyPopup)
			{
				NextUpdaterManager.removeNextUpdater(this)
				m_isReadyPopup = false
			}
			this.modify()
		}
		
		else if (!m_isReadyPopup)
		{
			NextUpdaterManager.addNextUpdater(this)
			m_isReadyPopup = true
		}
	}
	
	final public function close( destroy:Boolean = true ) : void
	{
		if (m_isReadyPopup)
		{
			NextUpdaterManager.removeNextUpdater(this)
			m_isReadyPopup = false
		}
		
		if (!m_multiFusion)
		{
			return
		}
		
		if (destroy)
		{
			m_multiFusion.kill()
			m_multiFusion = null
		}
		
		else
		{
			UIManager.m_monitor.removeChild(m_multiFusion.displayObject)
		}
		
		this.dispatchEvent(new PanelEvent(PanelEvent.CLOSE))
	}
	
	public function modify() : void
	{
		if (!m_multiFusion)
		{
			m_multiFusion = new MultiFusion()
			if (UIManager.m_pixelRatio != 1)
			{
				m_multiFusion.m_view.makeTransform(true, true)
			}
		}
		
		if (m_layer == -1)
		{
			UIManager.m_monitor.addChild(m_multiFusion.displayObject)
		}
		
		else
		{
			UIManager.m_monitor.addChildAt(m_multiFusion.displayObject,UIManager.m_monitor.numChildren + m_layer + 1)
		}
		
		m_multiFusion.setState(m_stateType, mStateArgs)
		this.dispatchEvent(new PanelEvent(PanelEvent.POPUP))
		mStateArgs = null
		m_isReadyPopup = false
	}
	
	
	internal var m_stateType:Class
	
	internal var m_multiFusion:MultiFusion
	
	internal var mStateArgs:Array
	
	internal var m_layer:int
	
	internal var m_isReadyPopup:Boolean
}